/*
	按键消抖模块
*/

module key_dithering(
 
	input		wire	 		clk,
	input 	wire 			ret_n,
	input		wire 			key_in,
	
	output 	reg 			key_stable

);

	reg [1:0] key_metasable_state;			//消除按键输入的亚稳态
	
	//对消除按键输入的亚稳态编写
	always @(posedge clk)
		begin 
			key_metasable_state[0] <= key_in;
			key_metasable_state[1] <= key_metasable_state[0];
		end 
		
	reg key_dithering;              //消除按键抖动
	
	//对消除按键抖动编写
	always @(posedge clk)
		key_dithering <= key_metasable_state[1];
		
		
	wire podge;								//上升沿
	wire nedge;                      //下降沿
	
	//对上升沿和下降沿的编写
	assign podge = !key_dithering &&  key_metasable_state[1];
	assign nedge =  key_dithering && !key_metasable_state[1];
	
	/*
		以下代码：利用状态机消除抖动 
	*/
	
	reg [19:0] cnt;						//判断按键输入是否稳定的计数器，当 cnt 计数到 999_999 时标志稳定
	reg en_cnt;								//计数器使能信号
	parameter cnt_max = 999_999;		//当 cnt 计数到 999_999 时标志稳定
	
	//对计数器进行编写
	always @(posedge clk or negedge ret_n)
		if(!ret_n)
			cnt <= 0;
		else if(en_cnt)
			cnt <= cnt + 1'b1;
		else 
			cnt <= 0;
	
	reg [2:0] state;						//状态机的状态变化量
	reg key_stable_signal;				//按键按下稳定后的标志信号
	//对状态机进行编写
	always @(posedge clk or negedge ret_n)
		if(!ret_n)
			begin 
				state  <= 3'd0;
				en_cnt <= 1'b0;
				key_stable_signal <= 1'b0;
			end 
		else 
			begin 
				case(state) 
					0 : begin 
							if(nedge) 									//等待下降沿，下降沿一来就跳转到状态1，并且计数器开始计数，否则就保持状态0
								begin 
									state  <= 3'd1;
									en_cnt <= 1'b1;
								end 
							else 
								state <= 3'd0;
						 end 
				
				   1 : begin 
							if(cnt > cnt_max)							//当计数器 cnt > cnt_max 时，跳转到状态2，否则当上升沿一来就跳转回状态0
								begin 
									state  <= 3'd2;
									en_cnt <= 1'b0;
									key_stable_signal <= 1'b1;
								end 
							else if(podge)
								begin 
									state  <= 3'd0;
									en_cnt <= 1'b0;
								end 
						 end 
						 
					2 : begin 
							if(podge)									//当上升沿到来时状态跳转到状态3，并且计数器开始计数，否则就一直等待上升沿
								begin 
									state  <= 3'd3;
									en_cnt <= 1'b1;
								end 
							else 
								begin 
									state <= 3'd2;
									key_stable_signal <= 1'b0; 
								end 
						 end
						 
					3 : begin 
							if(cnt > cnt_max)						   //当计数器 cnt > cnt_max 时，跳转到状态0，否则当上升沿一来就跳转回状态2
								begin 
									state  <= 3'd0;
									en_cnt <= 1'b0;
								end 
							else if(nedge)
								begin 
									state  <= 3'd2;
									en_cnt <= 1'b0;
								end 
						 end 
						 
					default : begin 
									state  <= 3'd0;
									en_cnt <= 1'b0;
									key_stable_signal <= 1'b0;
								 end 
				endcase
			end 
			
	//对按键消抖稳定后的状态进行寄存一拍后输出
	always @(posedge clk)
		key_stable <= key_stable_signal;
	
endmodule 
	



